﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace AiMoWindows.MainActions.ScriptActions.SubActions
{
    /// <summary>
    /// F12 快速找到定义处的代码
    /// </summary>
    class DefinitionQuickAction(ActionsController owner)
    {
        readonly ActionsController owner = owner;

        public async void GotoDefinition()
        {
            SyntaxToken selectedToken = await owner.GetCurrentSelectSyntaxToken();
            string variableName = selectedToken.ToString();
            if (string.IsNullOrEmpty(variableName))
            {
                owner.Printer.PrintDebug("Cannot goto definition without identifier token");
                return;
            }
            SyntaxNode root = await owner.GetCurrentSyntaxRoot();

            var classifiedSpans = await Classifier.GetClassifiedSpansAsync(owner.CurrentDocument, selectedToken.Span, CancellationToken.None);
            string currentType = classifiedSpans.FirstOrDefault().ClassificationType;
            SyntaxNode? definitionNode = null;
            switch (currentType)
            {
                case "local name":
                case "field name":
                    definitionNode = FindDeclaration<VariableDeclaratorSyntax>(root, selectedToken);
                    break;
                case "method name":
                    definitionNode = FindDeclaration<MethodDeclarationSyntax>(root, selectedToken);
                    break;
                case "class name":
                    definitionNode = FindDeclaration<ClassDeclarationSyntax>(root, selectedToken);
                    break;
                case "struct name":
                    definitionNode = FindDeclaration<StructDeclarationSyntax>(root, selectedToken);
                    break;
                case "interface name":
                    definitionNode = FindDeclaration<InterfaceDeclarationSyntax>(root, selectedToken);
                    break;
                case "enum name":
                    definitionNode = FindDeclaration<EnumDeclarationSyntax>(root, selectedToken);
                    break;
                case "property name":
                    definitionNode = FindDeclaration<PropertyDeclarationSyntax>(root, selectedToken);
                    break;
                default:
                    owner.Printer.PrintDebug($"Unknown {variableName}, type = {currentType}");
                    break;
            }
            SyntaxToken definitionToken = GetIdentifierToken(definitionNode);
            if (definitionNode == null || definitionToken.IsKind(SyntaxKind.None))
            {
                owner.Printer.PrintDebug($"Cannot find definition of \"{variableName}\"");
                return;
            }
            var location = definitionToken.GetLocation();
            int lineNumber = location.GetLineSpan().StartLinePosition.Line + 1;

            owner.Editor.ScrollToLine(lineNumber);
            owner.Editor.Select(location.SourceSpan.Start, location.SourceSpan.Length);
            return;
        }

        T? FindDeclaration<T>(SyntaxNode root, SyntaxToken selectedToken) where T : SyntaxNode
        {
            // 找到包含选定Token的语法节点
            var containingNode = root.FindNode(selectedToken.Span);

            // 获取变量名或标识符名
            string identifierName = selectedToken.ToString();

            // 从内向外遍历作用域，找到变量的定义
            while (containingNode != null)
            {
                // 在当前作用域中查找声明
                var declaration = containingNode
                    .DescendantNodes()
                    .OfType<T>()
                    .FirstOrDefault(x => GetIdentifierToken(x).Text == identifierName);

                if (declaration != null)
                {
                    return declaration;
                }

                // 移动到父作用域
                containingNode = containingNode.Parent;
            }

            return null;
        }
        SyntaxToken GetIdentifierToken(SyntaxNode? node)
        {
            switch (node)
            {
                case ClassDeclarationSyntax classDeclaration:
                    return classDeclaration.Identifier;
                case StructDeclarationSyntax structDeclaration:
                    return structDeclaration.Identifier;
                case InterfaceDeclarationSyntax interfaceDeclaration:
                    return interfaceDeclaration.Identifier;
                case MethodDeclarationSyntax methodDeclaration:
                    return methodDeclaration.Identifier;
                case EnumDeclarationSyntax enumDeclaration:
                    return enumDeclaration.Identifier;
                case PropertyDeclarationSyntax propertyDeclaration:
                    return propertyDeclaration.Identifier;
                case VariableDeclaratorSyntax variableDeclarator:
                    return variableDeclarator.Identifier;
                default:
                    return default;
            }
        }
    }

}
